package core;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.regex.*;
import multiplayer.lan.*;
import gui.GuiManager;
import gui.gui2d.ChessBoardPanel;
import gui.gui2d.eventsmanager.MouseListenerSelecterPiece;
import gui.gui2d.menu.events.MenuActionListener;
import utility.Color;
import utility.NameMemmory;
import world.gameMenager.GameManager;
import world.gameMenager.abstractFactory.*;
import world.player.*;
public class Core implements Observer {
	private GuiManager guiManager;
	private GameManager gameManager;
	private MenuActionListener menuListener;
	ServersOnAir soa;
	BroadcastListener bl;
	RoBotCleanerServers rcs;
	TcpObject tcpInstance;
	BroadcastPacketsDiscovery b;
	IAPlayer p2;
	public Core() {
		guiManager= new GuiManager();
		menuListener= new MenuActionListener();
		soa = new ServersOnAir();
		bl= new BroadcastListener(soa);
		rcs= new RoBotCleanerServers(soa);
	}
	private void start() {
		guiManager.loadMenuOnBackground();
		guiManager.loadListeners(menuListener);
		menuListener.addObserver(this);
		guiManager.setVisible();
		guiManager.setVisibleMenu();
	}
	public static void main(String[] args) {
		Core core= new Core();
		core.start();
	}
	void newLocalGame(){
		guiManager.loadLocalGame();
		guiManager.setWhiteTurn();
		Player p1=new LocalPlayer(Color.WHITE);
		Player p2=new LocalPlayer(Color.BLACK);
		gameManager= GameManagerFactory.getGameManager(new GameMenager1v1LocalFactory());
		gameManager.loadPiceOnMatrix();//Load matrix with initial position of chess
		ChessBoardPanel cbp = new ChessBoardPanel(gameManager.getChess().getChessBoardMenager());
		cbp.repaint();
		guiManager.repaintChessBoardPanel();
		guiManager.addChessBoardPanel(cbp);
		guiManager.repaintChessBoardPanel();
		p1.setGameManager(gameManager);
		p2.setGameManager(gameManager);
		MouseListenerSelecterPiece mlsp = new MouseListenerSelecterPiece();
		mlsp.addObserver(p1);
		mlsp.addObserver(p2);
		cbp.addObserver(p1);
		cbp.addObserver(p2);
		gameManager.setLastToPlay(p2);
		gameManager.addObserver(cbp);
		gameManager.addObserver(guiManager);
		guiManager.addListenerSelecterPiecePanel(mlsp);
		guiManager.addListenerOkExitPanel(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {}
			@Override
			public void mousePressed(MouseEvent e) {}
			@Override
			public void mouseExited(MouseEvent e) {}
			@Override
			public void mouseEntered(MouseEvent e) {}
			@Override
			public void mouseClicked(MouseEvent e) {
				guiManager.removeGamePanel();
				start();
				guiManager.setVisibleMenu();
			}
		});
	}
	private void openConnectionClient(){
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				tcpInstance = new TcpClient();
				guiManager.disableConnectionButton();
				guiManager.setInfoInConnection();
				tcpInstance.loadIp(guiManager.getIp());
				try {
					tcpInstance.connect();
				} catch (IOException e) {
					e.printStackTrace();
					guiManager.endInfoInConnection();
					guiManager.enableConnectionButton();
					return;
				}
				guiManager.endInfoInConnection();
				guiManager.loadRemoteGame();
				guiManager.setOpponentWait();
				bl.setTerminate(true);
				rcs.setTerminate(true);
				gameManager= GameManagerFactory.getGameManager(new GameMenagerOnLanFactory());
				gameManager.loadPiceOnMatrix();//Load matrix with initial position of chess
				ChessBoardPanel cbp = new ChessBoardPanel(gameManager.getChess().getChessBoardMenager());
				Player p1=new LocalPlayer(Color.WHITE);
				guiManager.infoNoError("connesso");
				guiManager.addChessBoardPanel(cbp);
				TcpClient tcpInstance1= (TcpClient)tcpInstance;
				Player p2=new RemotePlayer(Color.BLACK,tcpInstance1) ;
				tcpInstance1.addObserver(p2);
				gameManager.addObserver(cbp);
				p1.setGameManager(gameManager);
				p2.setGameManager(gameManager);
				tcpInstance1.loadIp(guiManager.getIp());
				Thread clientThread= new Thread(tcpInstance1);
				clientThread.start();
				cbp.addObserver(p1);
				gameManager.addObserver(p2);
				p1.setColor(Color.WHITE);
				p2.setColor(Color.BLACK);
				gameManager.setLastToPlay(p2);
				gameManager.addObserver(guiManager);
				MouseListenerSelecterPiece mlsp = new MouseListenerSelecterPiece();
				mlsp.addObserver(p1);
				guiManager.addListenerSelecterPiecePanel(mlsp);
				guiManager.addObserverSendButton(p1);
				guiManager.addListenerOkExitPanel(new MouseListener() {
					@Override
					public void mouseReleased(MouseEvent e) {}
					@Override
					public void mousePressed(MouseEvent e) {}
					@Override
					public void mouseExited(MouseEvent e) {}
					@Override
					public void mouseEntered(MouseEvent e) {}
					@Override
					public void mouseClicked(MouseEvent e) {
						start();
						tcpInstance.closeConnection();
					}
				});
			}
		});
		t.start();
	}
	void searchOnLan(){
		bl.setTerminate(false);
		rcs.setTerminate(false);
		Thread serverListener= new Thread(bl);
		Thread cleaner= new Thread(rcs);
		serverListener.start();
		cleaner.start();
		guiManager.loadSearchMenu(soa);
		guiManager.addListenerConnectionButton(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if(guiManager.getName().isEmpty()){
					guiManager.insertInfoOnLanServersMenager("Errore: Inserisci il nick!");
					return;
				}
				NameMemmory.getInstace().setNameInFile(guiManager.getName());
				if(guiManager.getIp().isEmpty()){
					guiManager.insertInfoOnLanServersMenager("Errore: Inserisci ip");
					return;
				}else if(guiManager.getIp().equals(" ")){
					guiManager.insertInfoOnLanServersMenager("Errore: Inserisci ip");
					return;
				}
				String ipPattern = 
						"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
								"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
								"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
								"([01]?\\d\\d?|2[0-4]\\d|25[0-5]):(\\d+)$";
				Pattern p = Pattern.compile(ipPattern);
				Matcher m = p.matcher(guiManager.getIp());
				boolean matchFound = m.matches();
				if (!matchFound){
					guiManager.insertInfoOnLanServersMenager("Errore: Ip errato!");
					return;
				}
				openConnectionClient();
			}
		});
		guiManager.addListenerBackButton(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {}
			@Override
			public void mousePressed(MouseEvent e) {}
			@Override
			public void mouseExited(MouseEvent e) {}
			@Override
			public void mouseEntered(MouseEvent e) {}
			@Override
			public void mouseClicked(MouseEvent e) {
				bl.setTerminate(true);
				rcs.setTerminate(true);
				start();
			}
		});
	}
	private void openConnectionServer(final int port){
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				tcpInstance = new TcpServer();
				gameManager= GameManagerFactory.getGameManager(new GameMenagerOnLanFactory());
				gameManager.loadPiceOnMatrix();
				Player p1=new LocalPlayer(Color.BLACK);
				TcpServer tcpServer=(TcpServer) tcpInstance;
				Player p2=new RemotePlayer(Color.WHITE,tcpServer);
				ChessBoardPanel cbp = new ChessBoardPanel(gameManager.getChess().getChessBoardMenager());
				gameManager.addObserver(cbp);
				p1.setGameManager(gameManager);
				p2.setGameManager(gameManager);
				b= new BroadcastPacketsDiscovery();
				b.setNick(NameMemmory.getInstace().getName());
				b.setPort(port);
				b.setDelay(3000);
				tcpServer.setPort(port);
				Thread broadcastRepeater= new Thread(b);
				broadcastRepeater.start();
				try {
					tcpServer.connect();
				} catch (IOException e) {
					e.printStackTrace();
					return;
				}
				b.setEnable(false);
				guiManager.loadRemoteGame();
				guiManager.setPlayerWait();
				guiManager.addChessBoardPanel(cbp);
				p1.setColor(Color.BLACK);
				p2.setColor(Color.WHITE);
				cbp.addObserver(p1);
				tcpServer.addObserver(p2);
				gameManager.addObserver(p2);
				gameManager.setLastToPlay(p1);
				gameManager.loadPiceOnMatrix();
				Thread tcpServerThread= new Thread(tcpServer);
				tcpServerThread.start();
				gameManager.addObserver(guiManager);
				MouseListenerSelecterPiece mlsp = new MouseListenerSelecterPiece();
				mlsp.addObserver(p1);
				guiManager.addListenerSelecterPiecePanel(mlsp);
				guiManager.addObserverSendButton(p1);
				guiManager.addListenerOkExitPanel(new MouseListener() {
					@Override
					public void mouseReleased(MouseEvent e) {}
					@Override
					public void mousePressed(MouseEvent e) {}
					@Override
					public void mouseExited(MouseEvent e) {}
					@Override
					public void mouseEntered(MouseEvent e) {}
					@Override
					public void mouseClicked(MouseEvent e) {
						start();
						tcpInstance.closeConnection();
					}
				});

			}
		});
		t.start();
	}
	private void newIaPlay() {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				guiManager.loadIAGame();
				guiManager.setOpponentWait();
				gameManager= GameManagerFactory.getGameManager(new GameMenagerVsPcFactory());
				gameManager.loadPiceOnMatrix();//Load matrix with initial position of chess
				ChessBoardPanel cbp = new ChessBoardPanel(gameManager.getChess().getChessBoardMenager());
				Player p1=new LocalPlayer(Color.WHITE);
				guiManager.addChessBoardPanel(cbp);
				p2=new IAPlayer(Color.BLACK) ;
				gameManager.addObserver(cbp);
				p1.setGameManager(gameManager);
				p2.setGameManager(gameManager);
				cbp.addObserver(p1);
				gameManager.addObserver(p1);
				gameManager.addObserver(p2);
				p1.setColor(Color.WHITE);
				p2.setColor(Color.BLACK);
				gameManager.setLastToPlay(p2);
				gameManager.addObserver(guiManager);
				MouseListenerSelecterPiece mlsp = new MouseListenerSelecterPiece();
				mlsp.addObserver(p1);
				guiManager.addListenerSelecterPiecePanel(mlsp);
				guiManager.addListenerOkExitPanel(new MouseListener() {
					@Override
					public void mouseReleased(MouseEvent e){}
					@Override
					public void mousePressed(MouseEvent e){}
					@Override
					public void mouseExited(MouseEvent e){}
					@Override
					public void mouseEntered(MouseEvent e){}
					@Override
					public void mouseClicked(MouseEvent e) {
						start();
						p2.stopEngine();
					}
				});
				guiManager.repaintChessBoardPanel();

			}
		});
		t.start();
	}

	void openServerOnLan(){
		guiManager.loadServerPanel();
		guiManager.addListenerServerButtonConnection(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {}
			@Override
			public void mousePressed(MouseEvent e) {}
			@Override
			public void mouseExited(MouseEvent e) {}
			@Override
			public void mouseEntered(MouseEvent e) {}
			@Override
			public void mouseClicked(MouseEvent e) {
				if(!guiManager.getNickServerPlayer().isEmpty()){
					NameMemmory.getInstace().setNameInFile(guiManager.getNickServerPlayer());
					try {
						int port= Integer.parseInt(guiManager.getServerPort());
						openConnectionServer(port);
					} catch (Exception e2) {
						openConnectionServer(8457);
					}
					guiManager.waitingForClient();
				}else{
					guiManager.setErrorNick();
				}
			}
		});
		guiManager.addListenerServerBackButton(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent arg0) {}
			@Override
			public void mousePressed(MouseEvent arg0) {}
			@Override
			public void mouseExited(MouseEvent arg0) {}
			@Override
			public void mouseEntered(MouseEvent arg0) {}
			@Override
			public void mouseClicked(MouseEvent arg0) {
				start();
			}
		});
		guiManager.addListenerServerBackButtonOnConnection(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent arg0) {}
			@Override
			public void mousePressed(MouseEvent arg0) {}
			@Override
			public void mouseExited(MouseEvent arg0) {}
			@Override
			public void mouseEntered(MouseEvent arg0) {}
			@Override
			public void mouseClicked(MouseEvent arg0) {
				guiManager.loadComponentMenu();
				b.setEnable(false);
				tcpInstance.disable();
				tcpInstance.closeConnection();
			}
		});
	}
	@Override
	public void update(Observable o, Object arg) {
		if(o instanceof MenuActionListener){
			String type= (String) arg;
			switch (type) {
			case "ia":{
				newIaPlay();
				break;
			}
			case "new":{
				newLocalGame();
				break;
			}
			case "lan_search":{
				searchOnLan();
				break;
			}
			case "lan_server":{
				openServerOnLan();
				break;
			}
			case "exit":{
				guiManager.dispose() ;
				System.exit(0);
				break;
			}

			default:{
				break;
			}
			}
		}
	}
}